Skip to content

函数柯里化 ​

本节目标:理解“函数柯里化”的核心思路,并能把它用于实际开发或面试表达。 函数柯里化(Currying)是一种将多个参数的函数转换为一系列使用一个参数的函数的技术。它是函数式编程中的一个重要概念,通过柯里化,可以将函数的调用进行部分应用,从而生成新的函数。这对于函数复用和构建更灵活的函数有很大帮助。

基本概念 假设有一个函数 f,它接收多个参数。通过柯里化,函数 f 可以被转换为一系列嵌套的函数,每个嵌套的函数只接收一个参数,然后返回一个新的函数,直到所有的参数都被接收并处理。

示例 下面是一个简单的例子,展示了如何将一个接收两个参数的函数进行柯里化。 function add(x, y) { return x + y; } console.log(add(2, 3)); // 输出: 5

柯里化函数 function curryAdd(x) { return function(y) { return x + y; }; } let addTwo = curryAdd(2); console.log(addTwo(3)); // 输出: 5 console.log(curryAdd(2)(3)); // 输出: 5

通用柯里化函数 为了更方便地对任意函数进行柯里化,可以实现一个通用的柯里化函数。 function curry(func) { return function curried(...args) { if (args.length >= func.length) { return func.apply(this, args); } else { return function(...nextArgs) { return curried.apply(this, args.concat(nextArgs)); }; } }; } // 示例 function multiply(a, b, c) { return a * b * c; } let curriedMultiply = curry(multiply); console.log(curriedMultiply(2)(3)(4)); // 输出: 24 console.log(curriedMultiply(2, 3)(4)); // 输出: 24 console.log(curriedMultiply(2)(3, 4)); // 输出: 24

实现解释

  1. curry 函数:接受一个普通函数 func 作为参数。
  2. curried 函数:返回一个新的函数 curried,该函数接收任意数量的参数。
  3. 参数长度检查:如果传入的参数数量大于或等于原始函数 func 的参数长度,则直接调用 func 并返回结果。
  4. 参数收集:如果传入的参数数量不足,则返回一个新的函数,该函数继续收集剩余的参数,直到参数数量足够为止。

柯里化的应用

  1. 参数复用:可以固定一些参数,生成新的函数,简化后续的调用。
  2. 延迟计算:通过柯里化,可以在不同的时间点传递参数,延迟函数的执行。
  3. 函数组合:柯里化可以与其他函数式编程技巧结合,构建更复杂的功能。

总结 柯里化是一种强大的技术,可以将函数的参数进行分步传递,生成新的函数。这种技术在函数式编程中非常常见,有助于构建更灵活和可复用的代码。通过实现一个通用的柯里化函数,可以轻松地将任意函数转换为柯里化函数,充分利用柯里化的优势。

创建柯里化函数的通用方式。
function curry(fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function () {
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);
        return fn.apply(null, finalArgs);
    };
}
curry()函数的主要工作就是将被返回函数的参数进行排序。注意这个函数并没有考虑到执行环境,所以调用apply()时第一个参数是null。curry()函数可以按以下方式应用:
function add(num1, num2) {
    return num1 + num2;
}
var curriedAdd = curry(add, 5);
alert(curriedAdd(3)); //8
你也可以像下面例子这样给出所有的函数参数:
function add(num1, num2) {
    return num1 + num2;
}
var curriedAdd = curry(add, 5, 12);
alert(curriedAdd()); //17
函数柯里化还常常作为函数绑定的一部分包含在其中,构造出更为复杂的bind()函数。例如:
function bind(fn, context) {
    var args = Array.prototype.slice.call(arguments, 2);
    return function () {
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);
        return fn.apply(context, finalArgs);
    };
}
对curry函数的主要更改在于传入的参数个数,以及它如何影响代码的结果。
curry()仅仅接受要包裹的函数作为参数,而bind同时接受函数和一个object对象。这表示给被绑定的函数的参数是从第三个开始而不是第二个。另一处更改是在倒数第3行将
object对象传给apply。
当使用bind()时,它会返回绑定到给定环境的函数,并且可能它其中某些函数參数已经被设好。当你想除了event对象再额外给事件处理程序传递参数时,这非常有用,例如:
var handler = {
    message: "Event handled",
    handleClick: function (name, event) {
        alert(this.message + ":" + name + ":" + event.type);
    }
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler, "my-btn"));
ECMAScript5的bind方法也实现函数柯里化,只要在this的值之后再传入另一个参数即可。
var handler = {
    message: "Event handled",
    handleClick: function (name, event) {
        alert(this.message + ":" + name + ":" + event.type);
    }
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler, "my-btn"));
JavaScript中的柯里化函数和绑定函数提供了强大的动态函数创建功能。使用bind()还是curry要根据是否需要object对象响应来决定。它们都能用于创建复杂算法和功能,当然两者都不应滥用,因为每个函数都会带来额外的开销。

==函数柯里化指的是一种技术,可以将多参数函数转换单参数函数。==
==我们写一个工厂方法,可将多参数函数转成单参数函数。==
function curry(fn, args) {
    // 获取函数需要的参数长度
    let length = fn.length;
    args = args || [];
    return function () {
        let subArgs = args.slice(0);
        // 拼接得到现有的所有参数
        for (let i = 0; i < arguments.length; i++) {
            subArgs.push(arguments[i]);
        }
        // 判断参数的长度是否已经满足函数所需参数的长度
        if (subArgs.length >= length) {
            // 如果满足,执行函数
            return fn.apply(this, subArgs);
        } else {
            // 如果不满足,递归返回科里化的函数,等待参数的传入
            return curry.call(this, fn, subArgs);
        }
    }
}
// es6 实现
function curry(fn, ...args) {
    return fn.length <= args.length ? fn(...args) : curry.bind(null, fn, ...args);
}

本站总访问 — 次